/*
 * Project: Sudoku Hint Engine for Android
 * Copyright (C) 2010-2013 Emanuel Moecklin
 * 
 * Available under the terms of the Lesser General Public License (LGPL)
 */
package com.onegravity.sudoku.solver.data;

import java.util.Collections;
import java.util.List;
import java.util.Vector;

public class ExtraRegionManager {
	
	public synchronized static List<ExtraRegionExtended> getExtraRegionsExtended(ExtraRegionType type, Grid grid) {
		List<ExtraRegion> extraRegions = ExtraRegionManager.getExtraRegions(type);
		List<ExtraRegionExtended> extraRegionsExt = new Vector<ExtraRegionExtended>();
		for (ExtraRegion extraRegion:extraRegions) {
			ExtraRegionExtended extraRegionExt = new ExtraRegionExtended(extraRegion, grid);
			extraRegionsExt.add(extraRegionExt);
		}
		return extraRegionsExt;
	}

	public synchronized static List<ExtraRegion> getExtraRegions(ExtraRegionType type) {
		switch (type) {
		case X: return regions_x();
		case HYPER: return regions_hyper();
		case PERCENT: return regions_percent();
		case CENTERDOT: return regions_centerdot();
		case ASTERISK: return regions_asterisk();
		case COLOR: return regions_color();
		default: return Collections.emptyList();
		}
	}

	// ****************************************** X-Sudoku *******************************************

	private static List<ExtraRegion> extraRegions_x;

	private static List<ExtraRegion> regions_x() {
		extraRegions_x = getRegions(extraRegions_x, diagonal(false, 1), diagonal(true, 2));
		return extraRegions_x;
	}

	// ****************************************** Hyper-Sudoku *******************************************

	private static List<ExtraRegion> extraRegions_hyper;
	
	private static List<ExtraRegion> regions_hyper() {
		extraRegions_hyper = getRegions(extraRegions_hyper, square(1, 1, 1), square(5, 1, 2), square(1, 5, 3), square(5, 5, 4)); 
		return extraRegions_hyper;
	}
	
	// ****************************************** Percent-Sudoku *******************************************

	private static List<ExtraRegion> extraRegions_percent;

	private static List<ExtraRegion> regions_percent() {
		extraRegions_percent = getRegions(extraRegions_percent, square(1, 1, 1), diagonal(true, 2), square(5, 5, 3)); 
		return extraRegions_percent;
	}

	// ****************************************** CenterDot-Sudoku *******************************************

	private static List<ExtraRegion> extraRegions_centerdot;

	private static List<ExtraRegion> regions_centerdot() {
		extraRegions_centerdot = getRegions(extraRegions_centerdot, centerdot(1)); 
		return extraRegions_centerdot;
	}

	// ****************************************** Asterisk-Sudoku *******************************************

	private static List<ExtraRegion> extraRegions_asterisk;

	private static List<ExtraRegion> regions_asterisk() {
		extraRegions_asterisk = getRegions(extraRegions_asterisk, asterisk(1)); 
		return extraRegions_asterisk;
	}

	// ****************************************** Color-Sudoku *******************************************

	private static List<ExtraRegion> extraRegions_color;

	private static List<ExtraRegion> regions_color() {
		extraRegions_color = getRegions(extraRegions_color, color(0, 1), color(1, 2), color(2, 3),
															color(3, 4), color(4, 5), color(5, 6),
															color(6, 7), color(7, 8), color(8, 9)); 
		return extraRegions_color;
	}

	// ****************************************** Common Stuff *******************************************

	private static List<ExtraRegion> getRegions(List<ExtraRegion> extraRegionsList, ExtraRegion... extraRegions) {
		if (extraRegionsList==null) {
			extraRegionsList = new Vector<ExtraRegion>();
			for (ExtraRegion extraRegion:extraRegions) {
				extraRegionsList.add(extraRegion);
			}
		}
		return extraRegionsList;
	}

	private static ExtraRegion diagonal(boolean reverse, int index) {
		List<CellPosition> positions = new Vector<CellPosition>();
		for (int i=0; i<9; i++) {
			positions.add(reverse ? new CellPosition(i, 8-i) : new CellPosition(i, i));
		}
		return new ExtraRegionImpl(positions, index);
	}

	private static ExtraRegion square(int rowOffset, int colOffset, int index) {
		List<CellPosition> positions = new Vector<CellPosition>();
		for (int row = rowOffset; row < rowOffset + 3; row++) {
			for (int col = colOffset; col < colOffset + 3; col++) {
				positions.add(new CellPosition(row, col));
			}
		}
		return new ExtraRegionImpl(positions, index);
	}

	private static ExtraRegion color(int nr, int index) {
		List<CellPosition> positions = new Vector<CellPosition>();
		int row = nr / 3;
		int col = nr % 3;
		for (int r = 0; r < 9; r += 3) {
			for (int c = 0; c < 9; c += 3) {
				positions.add(new CellPosition(col + c, row + r));
			}
		}
		return new ExtraRegionImpl(positions, index);
	}

	private static ExtraRegion centerdot(int index) {
		List<CellPosition> positions = new Vector<CellPosition>();
		positions.add(new CellPosition(1, 1));
		positions.add(new CellPosition(4, 1));
		positions.add(new CellPosition(7, 1));
		positions.add(new CellPosition(1, 4));
		positions.add(new CellPosition(4, 4));
		positions.add(new CellPosition(7, 4));
		positions.add(new CellPosition(1, 7));
		positions.add(new CellPosition(4, 7));
		positions.add(new CellPosition(7, 7));
		return new ExtraRegionImpl(positions, index);
	}

	private static ExtraRegion asterisk(int index) {
		List<CellPosition> positions = new Vector<CellPosition>();
		positions.add(new CellPosition(2, 2));
		positions.add(new CellPosition(4, 1));
		positions.add(new CellPosition(6, 2));
		positions.add(new CellPosition(1, 4));
		positions.add(new CellPosition(4, 4));
		positions.add(new CellPosition(7, 4));
		positions.add(new CellPosition(2, 6));
		positions.add(new CellPosition(4, 7));
		positions.add(new CellPosition(6, 6));
		return new ExtraRegionImpl(positions, index);
	}
}